//! # 核心安全抽象
//!
//! 本模块包含 RustCloud 安全框架的核心数据结构和错误类型定义。
//! 这些定义在整个 RustCloud 生态系统中保持一致，确保互操作性。

pub mod context;
pub mod principal;
pub mod resource;
pub mod errors;

// 重新导出核心类型
pub use context::AuthContext;
pub use principal::{Principal, PrincipalType};
pub use resource::Resource;
pub use errors::{AuthError, AuthResult, SecurityError, SecurityResult};

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;

    #[test]
    fn test_auth_context_creation() {
        let context = AuthContext::new(
            Default::default(),
            "POST".to_string(),
            "/api/login".to_string(),
            Some("192.168.1.100".to_string()),
        );
        
        assert_eq!(context.method, "POST");
        assert_eq!(context.uri, "/api/login");
        assert_eq!(context.remote_addr, Some("192.168.1.100".to_string()));
    }

    #[test]
    fn test_principal_creation_and_permissions() {
        let mut principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        );
        
        assert_eq!(principal.id, "user123");
        assert_eq!(principal.name, "John Doe");
        assert_eq!(principal.principal_type, PrincipalType::User);
        assert!(principal.roles.is_empty());
        assert!(principal.permissions.is_empty());
        
        // 测试权限添加
        principal = principal
            .add_role("admin".to_string())
            .add_permission("users:read".to_string())
            .add_permission("users:write".to_string());
        
        assert!(principal.has_role("admin"));
        assert!(principal.has_permission("users:read"));
        assert!(principal.has_permission("users:write"));
        assert!(!principal.has_permission("orders:read"));
    }

    #[test]
    fn test_resource_creation() {
        let resource = Resource::new(
            "user-service".to_string(),
            "/api/users".to_string(),
            "GET".to_string(),
        );
        
        assert_eq!(resource.service, "user-service");
        assert_eq!(resource.path, "/api/users");
        assert_eq!(resource.method, "GET");
        assert_eq!(resource.get_resource_id(), "user-service:GET:/api/users");
    }

    #[test]
    fn test_auth_context_headers() {
        #[cfg(feature = "axum-integration")]
        {
            use axum::http::HeaderMap;
            
            let mut headers = HeaderMap::new();
            headers.insert("authorization", "Bearer token123".parse().unwrap());
            headers.insert("x-api-key", "key456".parse().unwrap());
            
            let context = AuthContext::new(
                headers,
                "GET".to_string(),
                "/api/data".to_string(),
                None,
            );
            
            assert_eq!(context.get_bearer_token(), Some("token123".to_string()));
            assert_eq!(context.get_api_key(), Some("key456"));
        }
    }

    #[test]
    fn test_query_params() {
        let mut query_params = HashMap::new();
        query_params.insert("api_key".to_string(), "query_key789".to_string());
        
        let context = AuthContext::new(
            Default::default(),
            "GET".to_string(),
            "/api/data".to_string(),
            None,
        ).with_query_params(query_params);
        
        assert_eq!(context.get_api_key(), Some("query_key789"));
    }

    #[test]
    fn test_principal_expiry() {
        use std::time::{SystemTime, Duration};
        
        // 测试未过期的 Principal
        let future_time = SystemTime::now() + Duration::from_secs(3600);
        let principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        ).with_expiry(future_time);
        
        assert!(!principal.is_expired());
        
        // 测试已过期的 Principal
        let past_time = SystemTime::now() - Duration::from_secs(3600);
        let expired_principal = Principal::new(
            "user456".to_string(),
            "Jane Doe".to_string(),
            PrincipalType::User,
        ).with_expiry(past_time);
        
        assert!(expired_principal.is_expired());
    }

    #[test]
    fn test_error_types() {
        let auth_error = AuthError::AuthenticationFailed("Invalid credentials".to_string());
        assert!(matches!(auth_error, AuthError::AuthenticationFailed(_)));
        
        let security_error = SecurityError::InvalidCredentials("Bad password".to_string());
        assert!(matches!(security_error, SecurityError::InvalidCredentials(_)));
    }
}